package admin.ui;

import game.MatchStatistics;
import game.Player;

import java.util.List;

import admin.exceptions.*;

import connect4client.net.ConnectionController.CommunicationMethod;
import connect4client.net.servers.Server;
import core.PluginInfo;

/**
 * Proxy mediator
 * 
 * This class works as a remote proxy by interacting with the
 * GUIMediator. For every call, it sends a message through the
 * GUIMediator and waits until the GUIMediator receives the
 * answer and puts it in a queue. The proxy awakes, reads the
 * queue and uses that object as the return value of the method. 
 */
public class ProxyMediator {

	
	public ProxyMediator(GUIMediatorImpl guiMediator) {
		this.guiMediator = guiMediator;
	}
	
	
	public boolean authenticate(Server server, String userName, String password) {
		guiMediator.sendLoginMessage(CommunicationMethod.TCP, server, userName, password);
		
		return (Boolean) waitForResultOrException(Boolean.class);
	}

	
	@SuppressWarnings("unchecked")
	public List<Player> listPlayers(boolean showAll) {
		guiMediator.sendListPlayersMessage(showAll);
		
		Object result = waitForResultOrException(List.class);
		
		return (List<Player>) result;
	}
	
	
	@SuppressWarnings("unchecked")
	public Object[] userDetails(String login) throws UnknownUserException {
		guiMediator.sendUserDetailsMessage(login);
		
		Object result = waitForResultOrException(Object[].class);
		
		if (result instanceof UnknownUserException) {
			throw (UnknownUserException) result;
		}
		
		return (Object[]) result;
	}
	
	
	@SuppressWarnings("unchecked")
	public List<MatchStatistics> listMatchs() {
		guiMediator.sendListMatchsMessage();
		
		Object result = waitForResultOrException(List.class);
		
		return (List<MatchStatistics>) result;
	}
	
	
	@SuppressWarnings("unchecked")
	public List<PluginInfo> listPlugins() {
		guiMediator.sendListPluginsMessage();
		
		Object result = waitForResultOrException(List.class);
		
		return (List<PluginInfo>) result;
	}
	
	
	public boolean startPlugin(String pluginName) {
		guiMediator.sendStartPluginMessage(pluginName);
		
		Object result = waitForResultOrException(Boolean.class);
		
		return (Boolean) result;
	}
	
	
	public boolean stopPlugin(String pluginName) {
		guiMediator.sendStopPluginMessage(pluginName);
		
		Object result = waitForResultOrException(Boolean.class);
		
		return (Boolean) result;
	}
	
	
	public boolean createAccount(String login, String password, String role) throws InvalidRoleException, UserAlreadyExistsException, InsufficientPermissionsException {
		guiMediator.sendAccountCreateMessage(login, password, role);
		
		Object result = waitForResultOrException(Boolean.class);
		
		if (result instanceof InsufficientPermissionsException) {
			throw (InsufficientPermissionsException) result;
		} else if (result instanceof InvalidRoleException) {
			throw (InvalidRoleException) result;
		} else if (result instanceof UserAlreadyExistsException) {
			throw (UserAlreadyExistsException) result;
		}
		
		return (Boolean) result;
	}
	
	
	public boolean removeAccount(String login) throws InsufficientPermissionsException, UnknownUserException {
		guiMediator.sendAccountRemoveMessage(login);
		
		Object result = waitForResultOrException(Boolean.class);
		
		if (result instanceof InsufficientPermissionsException) {
			throw (InsufficientPermissionsException) result;
		} else if (result instanceof UnknownUserException) {
			throw (UnknownUserException) result;
		}
		
		return (Boolean) result;
	}
	
	
	public boolean editAccount(String login, String newPassword, String newRole) throws InsufficientPermissionsException, UnknownUserException, InvalidRoleException {
		guiMediator.sendAccountEditMessage(login, newPassword, newRole);
		
		Object result = waitForResultOrException(Boolean.class);
		
		if (result instanceof InsufficientPermissionsException) {
			throw (InsufficientPermissionsException) result;
		} else if (result instanceof UnknownUserException) {
			throw (UnknownUserException) result;
		} else if (result instanceof InvalidRoleException) {
			throw (InvalidRoleException) result;
		}
		
		return (Boolean) result;
	}
	
	
	private Object waitForResultOrException(Class<?> className) {
		
		while (true) {
			Object result = guiMediator.take();
			
			if (result instanceof Exception)
				return result;
			
			if (className.isInstance(result))
				return result;
		}
	}
	

	private GUIMediatorImpl guiMediator;
}
